Skip to content

Added global actor preference extraction#12

Merged
NSFatalError merged 2 commits into
mainfrom
feature/global-actor-isolation-preference
Aug 18, 2025
Merged

Added global actor preference extraction#12
NSFatalError merged 2 commits into
mainfrom
feature/global-actor-isolation-preference

Conversation

@NSFatalError

@NSFatalError NSFatalError commented Aug 18, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added configurable global actor isolation preference.
    • Introduced actor-type declaration building support.
  • Refactor
    • Parameter extraction now returns optionals instead of throwing; new extraction API added.
    • Access-control handling simplified with new computed properties and member-level rules.
    • Type/decl abstractions expanded to include attributes and updated protocol conformance.
  • Chores
    • Broadened SwiftSyntax version compatibility and updated dependency lock.
  • Tests
    • Expanded tests for optional/absent parameters, string extraction, and global actor isolation.

@NSFatalError NSFatalError self-assigned this Aug 18, 2025
@coderabbitai

coderabbitai Bot commented Aug 18, 2025

Copy link
Copy Markdown

Walkthrough

Updates SwiftSyntax bounds and lockfile hash; refactors access-control utilities and modifiers; introduces GlobalActorIsolationPreference and plumbing for actor isolation; adds ActorDeclBuilder and BasicDeclSyntax change; changes ParameterExtractor API and tests to use optionals and AttributeSyntax initializer; makes InheritingDeclaration Hashable.

Changes

Cohort / File(s) Summary of changes
Dependency versioning
Package.swift, Package.resolved
Raised swift-syntax upper bound to <604.0.0; updated Package.resolved originHash.
Access-control & modifiers
Sources/.../Syntax/Extensions/WithModifiersSyntax.swift, Sources/.../Builders/Declarations/Common/DeclBuilder.swift
Removed old accessControlLevel(inheritingDeclaration:maxAllowed); added computed accessControlLevel and setterAccessControlLevel, helper accessControlLevel(detail:), widened token/keyword visibility; DeclBuilder now computes/clamps ACL with guarded lookups and member-level rules.
Syntax protocol/type changes
Sources/.../Syntax/Custom/BasicDeclSyntax.swift, Sources/.../Syntax/Custom/TypeDeclSyntax.swift
BasicDeclSyntax now includes WithAttributesSyntax; TypeDeclSyntax now composes BasicDeclSyntax (instead of WithModifiersSyntax).
Global actor isolation & settings
Sources/.../Syntax/Helpers/GlobalActorIsolationPreference.swift, Sources/.../Builders/Declarations/Common/DeclBuilderSettings.swift
Added GlobalActorIsolationPreference enum (nonisolated / isolated(TypeSyntax)); DeclBuilderSettings gains public var globalActorIsolationPreference: GlobalActorIsolationPreference? and updated initializer to accept it.
Parameter extraction API & tests
Sources/.../Parameters/ParameterExtractor.swift, Tests/.../Parameters/ParameterExtractorTests.swift
ParameterExtractor now has init(from: AttributeSyntax), arguments optional, and expression/rawString/trailingClosure APIs return optionals; added globalActorIsolationPreference(withLabel:) parsing; tests updated/expanded for nil cases and new parsing behavior.
Actor declaration builder
Sources/.../Builders/Declarations/Types/ActorDeclBuilder.swift
Added public protocol ActorDeclBuilder: TypeDeclBuilder with var declaration: ActorDeclSyntax { get } and public var typeDeclaration: any TypeDeclSyntax { declaration } extension.
InheritingDeclaration conformance
Sources/.../Syntax/Helpers/InheritingDeclaration.swift
Declared public enum InheritingDeclaration: Hashable.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant AttributeSyntax
  participant ParameterExtractor
  participant GlobalActorIsolationPreference

  Caller->>ParameterExtractor: init(from: AttributeSyntax)
  ParameterExtractor->>AttributeSyntax: read arguments (may be nil)
  Caller->>ParameterExtractor: globalActorIsolationPreference(label)
  ParameterExtractor->>ParameterExtractor: expression(withLabel:)
  alt no expression found
    ParameterExtractor-->>Caller: nil
  else expression is NilLiteral
    ParameterExtractor-->>Caller: .nonisolated
  else expression is MemberAccess (type)
    ParameterExtractor-->>Caller: .isolated(TypeSyntax)
  else unexpected form
    ParameterExtractor-->>Caller: throw ParameterExtractionError
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I nibble tokens in the night,
I hop through mods and set them right. 🐇
Actors guard with isolation,
Options bloom across the nation.
Tests cheer softly as I bite. ✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/global-actor-isolation-preference

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (13)
Package.resolved (1)

2-2: Consider not committing Package.resolved for a library package.

For libraries, committing Package.resolved can constrain your consumers’ dependency resolution unnecessarily. If you want reproducible CI, keep it; otherwise, consider removing it and letting dependents resolve within your declared range.

Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift (1)

11-15: Add brief docs to clarify semantics (nil vs. nonisolated).

Consider documenting how this enum is intended to be used (e.g., nil at the call site meaning “unspecified,” .nonisolated meaning “explicitly nonisolated,” and .isolated(T) meaning “isolate to T”). This reduces ambiguity at integration points.

Suggested inline docs:

 public enum GlobalActorIsolationPreference: Hashable {
-
-    case nonisolated
-    case isolated(TypeSyntax)
+    /// Explicitly prefer nonisolated (e.g., the argument was present and `nil`)
+    case nonisolated
+    /// Explicitly isolate to the given global actor type (e.g., `SomeGlobalActor.self`)
+    case isolated(TypeSyntax)
 }
Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift (1)

16-22: Consider documenting the new setting to avoid misuse.

A short doc comment on the property and initializer parameters will help future readers understand the nil/.nonisolated/.isolated distinctions.

Suggested diff:

-    public var globalActorIsolationPreference: GlobalActorIsolationPreference?
+    /// Global actor isolation preference extracted from parameters (if any).
+    /// - nil: no preference specified by the user; builder may apply defaults.
+    /// - .nonisolated: user explicitly prefers `nonisolated`.
+    /// - .isolated(T): user explicitly prefers isolation to the given global actor type `T`.
+    public var globalActorIsolationPreference: GlobalActorIsolationPreference?
@@
-        accessControlLevel: AccessControlLevel,
-        globalActorIsolationPreference: GlobalActorIsolationPreference? = nil
+        accessControlLevel: AccessControlLevel,
+        globalActorIsolationPreference: GlobalActorIsolationPreference? = nil
     ) {
Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift (1)

36-41: Detail-based filtering is good; consider guarding against future tokenization changes

The detail?.detail.tokenKind match is tight and correct today. If SwiftSyntax adjusts tokenization of private(set) detail again, you’ll have a silent fallback to the primary ACL. The suggested fix above makes the resolution resilient without changing this helper. No code change required here beyond the setter fix.

Sources/PrincipleMacros/Syntax/Custom/BasicDeclSyntax.swift (1)

12-13: Adding WithAttributesSyntax is sensible; verify all BasicDeclSyntax adopters comply

Expanding BasicDeclSyntax to include WithAttributesSyntax is a good tightening of the abstraction. Ensure every site that provides any BasicDeclSyntax actually uses decls that conform to WithAttributesSyntax; otherwise you’ll get type constraint errors.

If you want, I can scan the repo for usages of any BasicDeclSyntax and list the concrete decl types to double-check conformance.

Sources/PrincipleMacros/Builders/Declarations/Types/ActorDeclBuilder.swift (1)

16-21: Minor: add a brief doc comment for discoverability

A short doc comment on typeDeclaration improves IDE discoverability and maintains parity with other builders.

     public var typeDeclaration: any TypeDeclSyntax {
-        declaration
+        // The concrete actor declaration treated as a general type declaration.
+        declaration
     }
Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift (2)

35-43: Member inheritance shortcut is fine; consider naming clarity and small guard refactor

Logic is sound. Two small readability tweaks:

  • Avoid shadowing settings (outer property) with let settings = settings.accessControlLevel (rename to aclSettings).
  • Precompute internalIndex once to avoid repeatedly searching Keyword.accessControlLevels if this path expands.

Optional refactor for naming clarity:

-        let settings = settings.accessControlLevel
+        let aclSettings = settings.accessControlLevel
         guard let accessControlLevel = basicDeclaration.accessControlLevel,
               let index = TokenKind.accessControlLevels.firstIndex(of: accessControlLevel.tokenKind),
-              let maxAllowedIndex = Keyword.accessControlLevels.firstIndex(of: settings.maxAllowed)
+              let maxAllowedIndex = Keyword.accessControlLevels.firstIndex(of: aclSettings.maxAllowed)
         else {
             return nil
         }
 ...
-        switch settings.inheritingDeclaration {
+        switch aclSettings.inheritingDeclaration {

48-57: String-interpolated AttributeSyntax is convenient; verify SwiftSyntaxBuilder isn’t required

let globalActor: AttributeSyntax = "@\(globalActor)" relies on string interpolation builders. If SwiftSyntaxBuilder is not imported in this target, this may fail to compile depending on SwiftSyntax version. If you hit that, either import SwiftSyntaxBuilder here or construct the attribute using initializers.

Otherwise, the overall isolation preference flow looks correct and the trailing space handling is consistent.

Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (3)

46-51: Drop unnecessary try if trailingClosure stops throwing

trailingClosure(withLabel:) currently has no throwing paths. If you accept the API cleanup suggested in the implementation, remove try here.

Apply this diff if you make trailingClosure non-throwing:

-        let extracted = try extractor.trailingClosure(withLabel: "operation")
+        let extracted = extractor.trailingClosure(withLabel: "operation")

54-59: Same here: remove try if trailingClosure becomes non-throwing

Keeps call sites tidy and signals there are no error paths.

Apply this diff if you make trailingClosure non-throwing:

-        let extracted = try extractor.trailingClosure(withLabel: "operation")
+        let extracted = extractor.trailingClosure(withLabel: "operation")

80-121: Add tests for AttributeSyntax initializer path

You’ve added ParameterExtractor.init(from: AttributeSyntax) but tests only cover freestanding macro expansions. Consider mirroring a couple of these tests using attributes to exercise that initializer.

Example to add (outside current hunks):

extension ParameterExtractorTests {
    private func makeExtractor(from attribute: AttributeSyntax) -> ParameterExtractor {
        ParameterExtractor(from: attribute)
    }

    @Test
    func testAttributeInit_GlobalActor_Nonisolated() throws {
        let attribute: AttributeSyntax = "@MyMacro(isolation: nil)"
        let extractor = makeExtractor(from: attribute)
        let extracted = try extractor.globalActorIsolationPreference(withLabel: "isolation")
        #expect(extracted == .nonisolated)
    }

    @Test
    func testAttributeInit_ExpressionExtraction() throws {
        let attribute: AttributeSyntax = "@MyMacro(value: Type.make())"
        let extractor = makeExtractor(from: attribute)
        let extracted = extractor.expression(withLabel: "value")
        let expected: ExprSyntax = "Type.make()"
        #expect(extracted?.description == expected.description)
    }
}

Would you like me to open a follow-up PR to add these?

Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (2)

40-47: Remove unused throws from trailingClosure(withLabel:)

There are no throwing paths in this method. Dropping throws clarifies the API and avoids unnecessary try at call sites.

Apply this diff:

-    public func trailingClosure(
-        withLabel label: TokenSyntax?
-    ) throws -> ExprSyntax? {
+    public func trailingClosure(
+        withLabel label: TokenSyntax?
+    ) -> ExprSyntax? {
         if let trailingClosure {
             return ExprSyntax(trailingClosure)
         }
         return expression(withLabel: label)
     }

Note: Update test call sites accordingly (remove try) as suggested in the tests review comments.


78-85: Minor simplification in .isolated detection

You can avoid re-wrapping declName and trim the base to prevent stray whitespace.

Apply this diff:

-        if let memberAccessExpression = MemberAccessExprSyntax(expression),
-           let referenceExpression = DeclReferenceExprSyntax(memberAccessExpression.declName),
-           referenceExpression.baseName.tokenKind == .keyword(.self),
-           let baseType = memberAccessExpression.base {
-            return .isolated("\(baseType)")
-        }
+        if let memberAccessExpression = MemberAccessExprSyntax(expression),
+           memberAccessExpression.declName.baseName.tokenKind == .keyword(.self),
+           let baseType = memberAccessExpression.base {
+            return .isolated("\(baseType.trimmed)")
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b2671db and d7597ba.

📒 Files selected for processing (12)
  • Package.resolved (1 hunks)
  • Package.swift (1 hunks)
  • Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift (1 hunks)
  • Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift (1 hunks)
  • Sources/PrincipleMacros/Builders/Declarations/Types/ActorDeclBuilder.swift (1 hunks)
  • Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (2 hunks)
  • Sources/PrincipleMacros/Syntax/Custom/BasicDeclSyntax.swift (1 hunks)
  • Sources/PrincipleMacros/Syntax/Custom/TypeDeclSyntax.swift (1 hunks)
  • Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift (1 hunks)
  • Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift (1 hunks)
  • Sources/PrincipleMacros/Syntax/Helpers/InheritingDeclaration.swift (1 hunks)
  • Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift (1)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (1)
  • globalActorIsolationPreference (67-86)
Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift (2)
Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift (1)
  • accessControlLevel (36-41)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (1)
  • globalActorIsolationPreference (67-86)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (2)
Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (1)
  • arguments (96-112)
Sources/PrincipleMacros/Builders/Expressions/AssociatedValuesListExprBuilder.swift (1)
  • expression (43-53)
Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (1)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (4)
  • expression (31-38)
  • trailingClosure (40-47)
  • rawString (49-65)
  • globalActorIsolationPreference (67-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-and-test (tvos)
  • GitHub Check: build-and-test (macos)
  • GitHub Check: build-and-test (maccatalyst)
  • GitHub Check: build-and-test (watchos)
  • GitHub Check: build-and-test (ios)
🔇 Additional comments (18)
Package.swift (1)

23-26: Widened swift-syntax upper bound to < 604.0.0 — verify cross-minor compatibility.

This broadens the allowed range from 600.x..<602.x to 600.x..<604.x. SwiftSyntax often has source-breaking changes across these minors. The current pin (Package.resolved) is 601.0.1, which is safe, but please ensure CI exercises at least one 602.x and 603.x toolchain to catch API drifts before consumers hit them.

Sources/PrincipleMacros/Syntax/Helpers/InheritingDeclaration.swift (1)

9-13: Hashable conformance looks good.

Simple, no behavioral change, and useful for set/map usage.

Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift (1)

14-15: Good addition: optional globalActorIsolationPreference captures absence vs. explicit choice.

The optional distinguishes “unspecified” (nil) from “explicitly nonisolated,” which aligns with the extractor’s behavior.

Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift (2)

46-51: LGTM: centralizing specifier and access-control token sets

Exposing TokenKind.typeScopeSpecifiers, TokenKind.accessControlLevels and their Keyword counterparts as internal constants is clean and works well with the index-based logic elsewhere.

Also applies to: 55-68


32-34: Support both keyword and identifier for setter ACL detection

SwiftSyntax can treat the “set” in private(set) as either a keyword or an identifier. To ensure we always detect the setter ACL, update setterAccessControlLevel to check both forms:

 public var setterAccessControlLevel: TokenSyntax? {
-    accessControlLevel(detail: .identifier("set")) ?? accessControlLevel
+    accessControlLevel(detail: .keyword(.set))
+        ?? accessControlLevel(detail: .identifier("set"))
+        ?? accessControlLevel
 }

Could you verify this against a declaration like

public private(set) var x: Int

to confirm the setter ACL resolves to private?

Sources/PrincipleMacros/Syntax/Custom/TypeDeclSyntax.swift (1)

11-14: Conformance via BasicDeclSyntax is cleaner; final-ness semantics look correct

Switching to BasicDeclSyntax keeps attributes and modifiers available without repeating constraints. isFinal for class/protocol/actor/enum/struct is consistent with Swift semantics.

Sources/PrincipleMacros/Builders/Declarations/Types/ActorDeclBuilder.swift (1)

11-14: Protocol shape looks good

Narrowing to ActorDeclSyntax via declaration is clear and consistent with existing builders.

Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (7)

22-25: Solid migration to optional expression API

Using optional chaining on the extracted expression matches the updated expression(withLabel:) -> ExprSyntax? signature and keeps assertions concise.


30-33: Unlabeled argument extraction verified

This validates the nil-label path and ensures the first unlabeled argument is returned. Good coverage.


35-41: Great addition: missing label returns nil

This regression guard will prevent accidental exceptions when an argument is absent.


72-77: Error-path test for raw string extraction is correct

This asserts the right failure mode when a non-string expression is supplied.


83-87: Nil isolation preference when missing

Good check ensuring absence of the parameter yields nil.


90-94: nil isolation correctly treated as .nonisolated

This test captures the intended semantics for an explicit nil isolation argument.


114-120: Good negative test for unexpected global-actor syntax

Ensures metatype (.Type) is rejected with the documented error.

Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (4)

13-15: Making arguments optional is the right call

This de-risks attribute forms without arguments and simplifies downstream checks.


21-29: AttributeSyntax initializer looks correct

Extracting .argumentList and explicitly setting trailingClosure to nil (attributes can’t have trailing closures) is the right behavior.


31-38: Optional-returning expression(withLabel:) is clean and predictable

The equality on trimmedDescription handles both labeled and unlabeled arguments (via nil == nil). This aligns with tests.


49-65: Raw-string extraction semantics are solid

Returning nil when absent and throwing on unexpected syntax type strikes a good balance between ergonomics and strictness.

Comment thread Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift
@codecov

codecov Bot commented Aug 18, 2025

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (5)

21-29: AttributeSyntax initializer looks correct; consider broader argument support or explicit docs

Today you only handle .argumentList and treat everything else as “no arguments”. That’s fine for typical attribute invocations, but attributes can also carry other argument forms (e.g., balanced tokens, string-style). Either:

  • Document that only labeled expression lists are supported, or
  • Expand handling to cover other valid cases and throw a targeted error when present but unsupported.

Would you like me to draft an expansion that throws when unsupported argument forms are encountered so failures are explicit rather than silently treated as “no args”?


31-38: expression(withLabel:) is clean; consider a convenience overload for string labels

The token-based label match is robust. For ergonomics at call sites (esp. in tests), consider adding an overload that takes String? and converts it to a TokenSyntax internally.

You can add this outside the changed segment:

// Convenience overload (optional)
public func expression(withLabel label: String?) -> ExprSyntax? {
    expression(withLabel: label.map { .identifier($0) })
}

40-47: throws is unnecessary here; drop it to signal semantics clearly

This method never throws anymore. Keeping throws forces callers to use try with no benefit and obscures the new “nil means not found” semantics.

Apply this diff:

-    public func trailingClosure(
-        withLabel label: TokenSyntax?
-    ) throws -> ExprSyntax? {
+    public func trailingClosure(
+        withLabel label: TokenSyntax?
+    ) -> ExprSyntax? {
         if let trailingClosure {
             return ExprSyntax(trailingClosure)
         }
         return expression(withLabel: label)
     }

If you’re intentionally preserving throws for source-compatibility, a brief comment explaining that would help future readers.


49-65: String extraction semantics are sensible; interpolation intentionally rejected

Returning nil when the argument is missing and throwing on non-literal strings (e.g., interpolations) is a good split that mirrors common macro expectations.

Minor style nit: you mix .as(T.self) and typed-view initializers elsewhere. Consider consistently using one style for readability.


67-85: Global-actor isolation preference: solid coverage for nil and Type.self; trim base for robustness

The detection for nil.nonisolated and Type.self.isolated("Type") is correct and matches the tests. To avoid incidental whitespace in the captured type, consider trimming the base expression before interpolation.

Apply this diff:

-        if let memberAccessExpression = MemberAccessExprSyntax(expression),
+        if let memberAccessExpression = MemberAccessExprSyntax(expression),
            memberAccessExpression.declName.baseName.tokenKind == .keyword(.self),
            let baseType = memberAccessExpression.base {
-            return .isolated("\(baseType)")
+            return .isolated("\(baseType.trimmed)")
         }

Optionally, if you plan to allow MainActor without .self in the future, you could add a path for DeclReferenceExprSyntax or a TypeExprSyntax before throwing.

Do you want a follow-up to support Type without .self?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d7597ba and 2985154.

📒 Files selected for processing (2)
  • Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift (1 hunks)
  • Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift
🧰 Additional context used
🧬 Code Graph Analysis (1)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (2)
Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift (1)
  • arguments (96-112)
Sources/PrincipleMacros/Builders/Expressions/AssociatedValuesListExprBuilder.swift (1)
  • expression (43-53)
🔇 Additional comments (1)
Sources/PrincipleMacros/Parameters/ParameterExtractor.swift (1)

13-13: Good encapsulation: making arguments optional and private is the right call

This aligns with the new optional-return API and keeps the surface area tight.

@NSFatalError NSFatalError merged commit ec4efb1 into main Aug 18, 2025
7 of 9 checks passed
@NSFatalError NSFatalError deleted the feature/global-actor-isolation-preference branch August 18, 2025 20:16
@coderabbitai coderabbitai Bot mentioned this pull request Nov 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant